<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Controllers\Api\Device\XYApi;
use App\Models\XcDevice;
use App\Models\XcUser;
use App\Models\XcUserXiche;
use App\Models\XcSiteWashMode;
use App\Models\XcSiteOrder;
use App\Models\XcUserRecharge;
use App\Models\XcUserConsumerDetails;
use App\Models\XcDeviceRunlog;
use App\Models\XcRenterContract;
use App\Models\XcOrderTimeTask;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Jobs\PushSiteOrderData;



/**
 * 洗车机设备管理控制层
 *
 */
class DeviceController extends Controller
{
    protected $res = ['code' => -1, 'msg' => 'failed'];

    /**
     * 扫洗车机二维码显示洗车模式列表，看用户选择哪种洗车模式
     * @return \Illuminate\Http\JsonResponse
     */ 
    public function detail(Request $request)
    {
        $res = ['code' => -1,'msg' => 'failed'];
        $open_id = $request->get("open_id");//用户微信 openid
        $open_sn = $request->get("open_sn");//设备外部编号
        $device  = XcDevice::where("open_sn", $open_sn)->with(['site' => function($query){
                        $query->with(["washmode"/* =>function($q){
                            $q->with("factorywashmode");
                        }*/]);
                    }])->first();
        if (empty($device)){
            $res['msg'] = '未找到该设备编号';
        }else{
            if (isset($device->site->status) && $device->site->status == 1){
                $res['msg']  = $device->site->msg;
                return response()->json($res);
            }else{
                $res['code'] = 0;
                $res['msg']  = 'success';
                $res['data'] = $device;
            }
        }
        Log::info('Scan Qrcode info, openid:'.$open_id.',open_sn,'.$open_sn.', device:', $device->toArray());
        return response()->json($res);
    }


    /**
     * 小程序页面，用户选择相应的支付方式后：生成订单 -> 发送指令给机器 -> 用户按清洗键
     * 
     * @param stirng  openid 微信用户 openid
     * @param string open_sn 设备对外设备编号 
     * @param int    swid    选择的哪种洗车模式
     * @param int    paymenttype 0/1:金额/积分  支付类型 
     * @return \Illuminate\Http\JsonResponse
     * 
     */ 
    public function saveorder(Request $request)
    {
        $res = ['code' => -1,'msg' => 'failed'];
        $openid             = $request->post("openid");//微信用户ID 
        $open_sn            = $request->post("open_sn");//设备对外的设备编号
        $type               = $request->get("type", 0);//0余额或积分;6表示即充即用;2,3,4年卡季卡月卡;5次卡
        $user_recharge_id   = $request->get("user_recharge_id", 0);//如果是年卡季卡月卡次才有值
        $recharge_setting_id = $request->get("recharge_setting_id", 0);//2,3,4,5年卡季卡月卡次卡才会有指定ID
        $swid               = $request->post("swid");//选择的哪种洗车模式
        $payment_type       = $request->post("payment_type", 0);//支付类型，0/1：余额/积分
        $total_fee = $points= 0;//本次订单花费多少积分
        $sitename           = '';//站点名称
        $renter_profit      = 0;//场租方分润金额

        //获得用户的信息，主要是余额和积分，判断用户选择的是否够支付当前的洗车模式金额
        $user           = XcUserXiche::where("openid", $openid)->first();
        $site_factory   = XcSiteWashMode::where("id", $swid)->first();
        $device         = XcDevice::where("open_sn", $open_sn)->with("site")->first();
        //如果用户不存在，则添加一个用户
        if (empty($user)) $user = XcUserXiche::create(['openid' => $openid]);
        //dd($site_factory->toArray());
        
        if ($payment_type == 0) $total_fee = $user->money;
        if ($payment_type == 1) $points = $user->userpoints;
        if (!empty($device->site)) $sitename = $device->site->name;

        //场租分润金额
        if (($type == 6 || $type == 0) && $total_fee > 0){
            $contract      = new XcRenterContract();
            $renter_profit = $contract->GetRenterProfit($total_fee,$site_factory->renter_id);
        }

        $order_sn  = OrderSN('');
        $device_no = $device->device_no??'';
        DB::beginTransaction();
        try{
            //写入订单表
            $order_arra = ['renter_id'  => $site_factory->renter_id,
                            'site_id'   => $site_factory->site_id,
                            'site_name' => $sitename,
                            'device_no' => $device_no,
                            'sw_id'     => $swid,
                            //'washing_type'=> $site_factory->washing_type,
                            'type'      => $type,
                            'user_recharge_id' => $user_recharge_id,
                            'recharge_setting_id' => $recharge_setting_id,
                            'user_id'   => $user->id??0,
                            'openid'    => $openid,
                            'mobile'    => $user->mobile??'',
                            'nickname'  => $user->nickname??'',
                            'order_sn'  => 'YM'.$order_sn??'',
                            'money'     => $total_fee??0,
                            'points'    => $points??0,
                            'renter_profit' => $renter_profit,
                            'source'    => 'ym'
                        ];
            //dd($order_arra);
            $xc_order = XcSiteOrder::create($order_arra);
            
            Log::info('make site order data :', $xc_order->toArray());

            //和之前的流程不一样，产品原型：用户扫码后，用户选择余额，积分，次卡后，直接通过接品发送指令给机器，可以洗车
            //前期，只有余额，所以默认余额选中，用户只需要单击启动机器就可以了。
            $xiaoyu = new XYApi();
            $apires = $xiaoyu->SignleStart($order_sn, $device_no, $total_fee*100);
            //$apires = ['code' => 1, 'msg' => '设备预计在5分钟内启动成功！'];
            Log::info('yumai api return result data :'.json_encode($apires));
            if ($apires['code'] == 1){
                $res['code'] = 0;
                $res['msg'] = $apires['msg']; 
            }else{
                $res['msg'] = $apires['msg'];
            }

            DB::commit();
            return response()->json($res);
        }catch (\Exception $exception){
            DB::rollback();
            return response()->json(['code' => -1,'msg' => $exception->getMessage()]);
        }

    }

    /**
     * 机器启动后回调
     * 
     */ 
    public function start_callback(Request $request)
    {
        $data = $request->all();
        Log::info('yumai api start callback data :'.json_encode($data));
        $order_sn = 'YM'.$data['order_id'];
        $siteorder = XcSiteOrder::where("order_sn", $order_sn)->update(['fee_id' => $data['fee_id']??0,'start_time' => date("Y-m-d H:i:s")]);

        return response()->json($data); 
    }

    /**
     * 机器结算后的回调,后需要进行金额扣除等相关操作
     * 
     */ 
    public function end_callback(Request $request)
    {
        $res = ['code' => -1,'msg' => 'failed'];
        $data = $request->all();
        Log::info('yumai api end callback data :'.json_encode($data));

        $order_sn = 'YM'.$data['order_id'];
        $update = ['status' => 1]; 
        $order = XcSiteOrder::where("order_sn", $order_sn)->first();
        if (empty($order))  return response()->json($data);
        if ($order->status == 1){//已处理
            Log::info('yumai api end callback order status is 1 '.date("Y-m-d H:i:s"));
            return response()->json($data);
        }
        
        DB::beginTransaction();
        try{
            
            $money_out = $data['money_out'];//可能是金额，也可能是积分
            $xf_money = round($money_out/100,2);//消费金额，传递过来的单位是分
            
            //如果是订单是即充即用，或者扣除余额或积分
            if ($order->type == 0){
                $xcuser = XcUserXiche::where("id", $order->user_id)->first();
                Log::info('update before xcuser info :'.json_encode($xcuser->toArray()));
                //如果订单生成的金额，则扣除用户的相应余额
                if ($order->money > 0){
                    $money = $xcuser->money - $xf_money;
                    if ($money < 0) $money = 0;
                    $flag = $xcuser->update(['money' => round($money,2)]);
                    //更新订单的实际金额
                    $update['money'] = $xf_money;
                } 
                //如果订单生成的积分，则扣除用户的相应积分
                if ($order->points > 0){
                    $points = $xcuser->userpoints - intval($money_out);
                    if ($points < 0) $points = 0;
                    $flag = $xcuser->update(['userpoints' => $points]);
                    //更新订单的实际积分
                    $update['points'] = $money_out;
                }
                Log::info('update done xcuser info :'.json_encode($xcuser->toArray()));
            }else if (in_array($order->type, [2,3,4,5])){//2年卡3季卡4月卡5次卡

            }
            $order->update($update);

            /*暂时屏蔽,等公司统一开通再放开下面的脚本
            //查询更新后的订单数据，再异步post给雨熙那边的接口
            $order = XcSiteOrder::where("order_sn", $order_sn)->first();
            if ($order->money > 0){
                //异步调用，把消费数据给雨熙那边的接口
                PushSiteOrderData::dispatch($order);
            }
            */

            DB::commit();
            //return response()->json($data);
        }catch (\Exception $exception){
            DB::rollback();
            return response()->json(['code' => -1,'msg' => $exception->getMessage()]);
        }

        return response()->json($data); 
    }


    /**
     * 下成是自动洗车机流程，本来改改再用，现在流程不一样，暂不用
     *
     * @param Request $request
     * @param string open_sn    设备对外编号
     * @param string order_sn   订单编号
     * @param string openid     用户微信openid
     *      
     * @return \Illuminate\Http\JsonResponse
     */
    public function start(Request $request)
    {
        $res = ['code' => -1,'msg' => 'failed'];
        $open_sn = $request->get("open_sn");//设备外部编号 
        $order_sn = $request->get("order_sn");//支付后的订单号
        $openid = $request->get("openid");// 微信用户 openid
        $factory_api = $this->getfactoryclass($open_sn);

        //获取订单信息
        $order = XcSiteOrder::where("order_sn", $order_sn)
                    ->where('openid', $openid)->with(['device','washmode'])->first();
        $xcuser = XcUser::where(['openid' => $openid]);
        //dd($order->toArray());
        $checkres = $this->CheckSiteOrderVaild($order, $xcuser);
        if ($checkres['code'] == -1) return response()->json($checkres);
        $minutes = $order->washmode->minutes;

        //启动机器-发送指令给机器
        $total_fee = $this->ConverToTotalFee($xcuser, $order);
        //$device_no = $order->device_no;
        //$xiaoyu = new XYApi();
        //$apires = $jiejie->SignleStart($order_sn, $device_no, $total_fee);
        //模拟启动成功接口
        $apires['result'] = 1;
        $apires['err_msg'] = '';
        //如果启动成功，则处理订单状态，金额和积分减去相应的金额
        if ($apires['result'] == 1){
            DB::beginTransaction();
            try{
                //用户金额积分消费日志
                $ucd        = new XcUserConsumerDetails();
                $xcuser     = $xcuser->first();
                $user_id    = $xcuser->id;
                $site_name  = $order->site_name;
                $order_no   = $order->order_sn;
                $washing_type   = $order->washing_type;//1/2：快洗/精洗

                //如果是订单是即充即用，或者扣除余额或积分
                if (in_array($order->type, [0,6])){
                    Log::info('update before xcuser info :', $xcuser->toArray());
                    //如果订单生成的金额，则扣除用户的相应余额
                    $change_type = 1;
                    $num         = 0;
                    if ($order->money > 0){
                        $num = $order->money;
                        $money = $xcuser->money - round($order->money,1);
                        if ($money < 0) $money = 0;
                        $flag = $xcuser->update(['money' => $money]);
                    } 
                    //如果订单生成的积分，则扣除用户的相应积分
                    if ($order->points > 0){
                        $num = $order->points;
                        $points = $xcuser->userpoints - intval($order->points);
                        if ($points < 0) $points = 0;
                        $flag = $xcuser->update(['userpoints' => $points]);
                        $change_type = 2;
                    }
                    Log::info('update done xcuser info :', $xcuser->toArray());
                    $flag = XcSiteOrder::where(['order_sn' => $order_sn])->update(['status' => 1]);
                    $flagc = XcUserRecharge::where(['site_order_sn' => $order_sn])->update(['status' => 3]);

                    $flagd = $ucd->changeLog($user_id, $num, 2, $order_no, $change_type, $site_name,0, $washing_type);
                //如果是扣除年卡、季卡、月卡、次卡;此业务暂满足不了，看后续第三是否能完成开发远程指令的功能，即强行结算,代码暂注释
                }/*else if (in_array($order->type, [2,3,4,5])){
                    $flag = XcSiteOrder::where(['order_sn' => $order_sn])->update(['status' => 1]);
                    Log::info('update site order, order_sn:'.$order_sn.',oreder type:'.$order->type.', update status:'.$flag);
                    $ur = XcUserRecharge::where('id', $order->user_recharge_id);
                    if ($order->washing_type == 1){
                        $flag = $ur->update(['used_fast_washing_num' => DB::raw('used_fast_washing_num + 1')]);
                    }else if ($order->washing_type == 2){
                        $flag = $ur->update(['used_fast_washing_num' => DB::raw('used_fast_washing_num + 1')]);
                    }
                    Log::info('update user recharge, id:'.$order->user_recharge_id.',oreder type:'.$order->type.',washing type:'.$order->washing_type.' update status:'.$flag);
                    //如果是扣除的是次卡，还要写入日志表
                    if ($order->type == 5){
                        $flagd = $ucd->changeLog($user_id, 1, 2, $order_no,3,$site_name,0, $washing_type);
                    }
                }*/
                

                $res['code'] =0;
                $res['msg'] = '启动成功';
                $res['minutes'] = $minutes;
                Log::info('update siteorder table status:'.$flag.';start device result:', $res);

                DB::commit();
                return response()->json($res);
            }catch (\Exception $exception){
                DB::rollback();
                return response()->json(['code' => -1,'msg' => $exception->getMessage()]);
            }
        }else{
            $res['msg'] = $apires['err_msg'];
        }   
               

        return response()->json($res);
    }

    /**
     * 应用场景：主要是用于用户年卡、季卡、月卡、次卡，当用户
     * 订单计时任务，需要写入到MySQL，再写入Redis，后每隔2秒查询一下Redis，直到end_time到时后，删除Redis和Mysql
     * 
     */ 
    private function OrderTimeTask($order)
    {
        $user_recharge = XcUserRecharge::where('id', $order->user_recharge_id)->first();
        $once_washing_second = intval($user_recharge->once_washing_second);
        $data = ['order_id' => $order->id,
                 'type'     => $order->type,
                 'order_sn' => $order->order_sn,
                 'start_time'=> date("Y-m-d H:i:s"),
                 'end_time'  => date('Y-m-d H:i:s',strtotime('+'.$once_washing_second.'second')),
                ];

        $ott = XcOrderTimeTask::Create($data);
        return true;
    }

    /**
     * 把用户的余额、积分、次卡、年卡、季卡、月卡转换为机器的金额，区别如下：
     * 余额 = 用户帐号余额*100 $xcuser->money*100  因为存在帐号里面的是元，机器传递的是分，相关100倍
     * 积分 = 用户帐号积分     $xcuser->point/10   以前规则积分和金额的比例是1:10
     * 年卡/季卡/月卡/次卡 = 用户年卡/季卡/月卡/次卡信息     $_user_recharge->once_washing_second*1.667
     * 
     * 目前这个功能暂不能应用，第三方业务上满足不了，后续看他们是否能开发出远程指令的功能再来改善。
     * 
     */ 
    private function ConverToTotalFee($xcuser, $siteorder)
    {
        $money = 0;
        if ($siteorder->type == 0){
            $money = $xcuser->money*100;
        }else if (in_array($siteorder->type, [2,3,4,5])){
            $money = intval($siteorder->once_washing_second*1.667);
        }

        return $money;
    }

    /**
     * 判断订单的合理性，订单金额/积分是否满足启动机器，
     * 
     */ 
    private function CheckSiteOrderVaild($order, $xcuser)
    {
        //$flag = false;
        $res = ['code' => -1,'msg' => 'failed'];


        if (empty($order)){
            $res['msg'] = '订单号不存在';
            return $res; 
        }

        if ($order->status == 1){
            $res['msg'] = '该订单已使用过';
            return $res; 
        }

        $device_no = $order->device_no??'';
        if (empty($device_no)){
            $res['msg'] = '订单设备编号不存在';
            return $res; 
        }

        if (empty($order->washmode)){
            $res['msg'] = '订单洗swid必须大于0';
            return $res; 
        }

        if (in_array($order->type, [0,6])){
            $xcuser = $xcuser->first();
            if ($xcuser->money > 0){
                $res['msg'] = '余额不足,如果已充值请等待5到10秒后再试';
                return $res; 
            }

            if ( $xcuser->userpoints > 100){
                $res['msg'] = '积分需达到100积分才能使用';
                return $res; 
            }
        }
        

        return ['code' => 0,'msg' => 'success']; 

    }

    /**
     * 停止洗车机
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function stop(Request $request)
    {
        $res = ['code' => -1,'msg' => 'failed'];
        $device_no = $request->get("device_no", "");
        return response()->json($res);
    }



    /**
     * 查询传递过来设备的状态
     * open_sn : XY92jkf543
     * 通过设备编号前两个来区分是哪个厂商
     * 
     * @param  Request $request 传递过来的参数 
     * @return json            返回结果 
     */
    public function status(Request $request)
    {
        $res = ['code' => -1,  'msg' => 'failed'];
        $open_sn        = $request->get("open_sn");
        //换取数据里面真正的设备编号
        $xcdevice      = XcDevice::where("open_sn", $open_sn)->first();
        if (empty($xcdevice)){
            $res['msg']  = 'open_sn不存在';
            return response()->json($res);
        }
        //判断机器设备编号前两个字母是 jj(捷洁) 还是 hk(嗨卡) 
        $factory_bname  = substr($open_sn, 0, 2);
        $factory_api    = $this->getfactoryclass($factory_bname);
        $device_no      = $xcdevice->device_no;
        if (empty($device_no)){
            $res['msg']  = '未绑定机器编号';
            return response()->json($res);
        }
        //如果是捷叶，则调用捷洁的方法
        if ($factory_bname == 'YM'){
            $apires         = $factory_api->DeviceStatus($device_no);
            //return response()->json($apires);
            $data = ['water' => 1,//默认机器有水
                     'power' => 1,//默认电源正常
                     'connct' => 1,//默认网络联接正常
                     'used' => 0,//默认机器没有被人使用
                     'signal' => 0//默认sim卡信号强度
                    ];
                    // dd($apires);
             $apires_data = $apires['data'];
            if ($apires['code'] == 1){
                if (substr($apires_data['databin1'], 0,1) == 0 ) $data['water'] = 0; 
                if (substr($apires_data['databin1'], -1) == 0 ) $data['power'] = 0; 
                if ($apires_data['ConnectOK'] == 0 ) $data['connct'] = 0; 
                if ($apires_data['use_state'] == 2 ) $data['connct'] = 1; 
                $data['signal'] = $apires_data['data03']??0; 

                $res['code'] = 0;
                $res['msg']  = 'success';
                $res['data'] = $data;
            }
        }
    
        return response()->json($res);
    }

    /**
     * 查询所有在线的设备
     * @param  Request $request 请求数据
     * @return JOSN            成功返回所有在线的设备编号，否则给出错误提示
     */
    public function onlinedevice(Request $request)
    {
        $res = ['code' => -1, 'msg' => 'failed'];

        
        $factory_api    = $this->getfactoryclass("YM");
        $data = $factory_api->GetDeviceList();
        if ($data['code'] == 1){
            $res = ['code' => 0,
                    'msg'  => 'success',
                    'data' => $data['data']
                    ];
        }else{
            $res['msg'] = $data['msg'];
        }

        
        return response()->json($res);
    }


    public function runlog(Request $request)
    {

        $open_sn        = $request->get("open_sn");
        $starttime      = $request->get("starttime");
        $endtime        = $request->get("endtime");

        $factory_bname  = substr($open_sn, 0, 2);
        $factory_api    = $this->getfactoryclass($factory_bname);
        //换取数据里面真正的设备编号
        $xcdevice      = XcDevice::where("open_sn", $open_sn)->first();
        $device_no      = $xcdevice->device_no;
        if ($factory_bname == 'jj'){
            $orderlist =$factory_api->CoinRecord($device_no, 'coin_in', $starttime, $endtime,  0, 30);
            $this->res['code'] = 0;
            $this->res['msg']  = 'success';
            $this->res['data'] = $orderlist;
        }

        return response()->json($this->res);
    }

    private function getfactoryclass( $str = 'jj')
    {
        $factory_api = [];
        $prefix  = substr($str, 0, 2);
        //如果是捷洁的设备
        if ($prefix == "jj"){
            $factory_api = JiejieApi::getInstance();
        }else if ($prefix == "YM"){//如果是嗨卡
            $factory_api = XYApi::getInstance();
        }
        return $factory_api;
    }









}